package stmlib;
import java.util.*;

/** A Transactional Random Access java.util.List.  Protected by a ReadWriteLock. */
public class StmList<E> extends Lockable implements List<E>, RandomAccess {
    final List<E> list;
    public StmList (List <E> list, LockManager lm) { this.list = list; this.lm = lm; }
    public StmList () { this.list = new ArrayList<E>(); this.lm = new LockManager(); }
    public E get(int index) { lm.readLock(); return list.get(index); }
    public StmList<E> subList(int fromIndex, int toIndex) {
        return new StmList<E>(list.subList(fromIndex, toIndex), lm);
    }
    public ListIterator<E> listIterator(int index) { return
            new StmListIterator<E>(list.listIterator(index), lm); }
    public ListIterator<E> listIterator() { return listIterator(0); } //how efficient?
    public Iterator<E> iterator() { return new StmIterator<E>(list.iterator(), lm); }
    public int lastIndexOf(Object o) { lm.readLock(); return list.lastIndexOf(o); }
    public int indexOf(Object o) { lm.readLock(); return list.indexOf(o); }
    public boolean contains (Object o) { lm.readLock(); return list.contains(o);}
    public boolean containsAll(Collection<?> c) { lm.readLock(); return list.containsAll(c); }
    public boolean isEmpty() { lm.readLock(); return list.isEmpty(); }
    public int size() { lm.readLock(); return list.size(); }
    public E remove(final int index) {
        lm.writeLock();
        final E oldValue = list.remove(index);
        lm.logUndo(new Runnable() { public void run() {
            list.add(index, oldValue);
        }});
        return oldValue;
    }

    public boolean addAll(final int index, Collection<? extends E> c) {
        final int size = c.size();
        if (size == 0) return false;
        else {
            lm.writeLock();
            list.addAll(index, c);
            lm.logUndo(new Runnable() { public void run() {
                list.subList(index, index + size).clear();
            }});
            return true;
        }
    }
    @Override
    public boolean addAll(Collection<? extends E> c) { return addAll(0, c); }

    @Override
    public void add(final int index, E element) {
        lm.writeLock();
        list.add(index, element);
        lm.logUndo(new Runnable() { public void run() {
            list.remove(index);
        }});
    }
    public boolean add(E element) { 
        lm.writeLock(); add(list.size(), element); return true; }

    public E set(final int index, E element) {
        lm.writeLock();
        final E oldVal = list.set(index, element);
        lm.logUndo(new Runnable() { public void run() {
            list.set(index, oldVal);
        }});
        return oldVal;
    }
    public void clear() {
        lm.writeLock();
        final ArrayList<E> oldContents = new ArrayList<E>();
        oldContents.addAll(list);
        list.clear();
        lm.logUndo(new Runnable() { public void run() {
            list.addAll(oldContents);
        }});
    }
    public Object[] toArray() { lm.readLock(); return list.toArray(); }
    public <T> T[] toArray(T[] a) { lm.readLock(); return list.toArray(a); }

    public boolean removeAll(Collection<?> c) { throw new UnsupportedOperationException("slow"); }
    public boolean retainAll(Collection<?> c) { throw new UnsupportedOperationException("slow"); }
    public boolean remove(Object o) { throw new UnsupportedOperationException("slow"); }

    @Override
    public String toString() { return toString(list); }
    @Override
    public StmList<E> lock() { lm.writeLock(); return this; }
}
